#include "records.h"


void RecordFile::WriteLock() {
  CHECK(lock_state_ == F_UNLCK);
  lock_state_ = lock_.l_type = F_WRLCK;
  fcntl(fd_, F_SETLKW, &lock_);
}
void RecordFile::ReadLock() {
  CHECK(lock_state_ == F_UNLCK);
  lock_state_ = lock_.l_type = F_RDLCK;
  fcntl(fd_, F_SETLKW, &lock_);
}
void RecordFile::Unlock() {
  CHECK(lock_state_ != F_UNLCK);
  lock_state_ = lock_.l_type = F_UNLCK;
  fcntl(fd_, F_SETLKW, &lock_);
}

void RecordFile::WriteRecord(string s) {
  // re-enable this check if you want to write from multiple processes
  //  CHECK(lock_state_ == F_WRLCK);
  uint64 len = s.size();
  CHECK(write(fd_, &len, sizeof(uint64)));
  CHECK(write(fd_, s.c_str(), len));
}

void RecordFile::Read(){
  // CHECK(lock_state_ != F_UNLCK);
  //   lseek(fd_, next_record_start_, SEEK_SET);
  string s;
  char buf[1000000];
  while (1) {
    int bytes_read = read(fd_, buf, 1000000);
    if (bytes_read == 0) break;
    s += string(buf, bytes_read);
  } 
  next_record_start_ += s.size();
  const char * p = s.c_str();
  while (p != s.c_str() + s.size()) {
    uint64 size;
    memcpy(&size, p, sizeof(uint64));
    p += sizeof(uint64);
    records_read_.push_back(string(p, size));
    p += size;
  }
  //lseek(fd_, next_record_start_, SEEK_SET);
}

string RecordFile::PopRecord() {
  CHECK(RecordsAvailable());
  string s = records_read_.front();
  records_read_.pop_front();
  return s;
}


int records_main(int argc, char ** argv) {
  RecordFile r("foo");
  /*
  int n = atoi(argv[1]);
  int total_records = 0;
  for (int i=0; i<1000000; i++) {
    if (i % 100000 == 0) cout << "wrote " << i << " records" << endl;
    ostringstream ostr;
    ostr << (i * 10 + n); 
    r.WriteRecord(ostr.str());
    r.Read();
    while (r.RecordsAvailable()) {
      r.PopRecord();
      total_records++;
    }
  }
  cout << "total records read: " << total_records << endl;
  */
  string command;
  while (cin >> command) {
    if (command == "read") {
      r.Read();
      while (r.RecordsAvailable()) 
	cout << "read record " << r.PopRecord() << endl;
      cout << "done reading" << endl;
    }
    if (command == "write") {
      string s;
      cin >> s;
      r.WriteRecord(s);
      cout << "Wrote " << s << endl;
    }    
    if (command == "rl") {
      r.ReadLock();
      cout << "Acquired read lock" << endl;
    }
    if (command == "wl") {
      r.WriteLock();
      cout << "Acquired write lock" << endl;
    }
    if (command == "ul") {
      r.Unlock();
      cout << "Unlocked" << endl;
    }
    cout << "Position = " << r.Pos() << endl;
  }

  return 0;
}
